package com.ktjy.springsecuitydemo.config;

import com.ktjy.springsecuitydemo.handle.MyAccessDeniedHandler;
import com.ktjy.springsecuitydemo.handle.MyAuthenticationFailureHandler;
import com.ktjy.springsecuitydemo.handle.MyAuthenticationSuccessHandler;
import com.ktjy.springsecuitydemo.service.UserDetailsServiceImpl;
import jakarta.annotation.Resource;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.security.config.Customizer;
import org.springframework.security.config.annotation.web.builders.HttpSecurity;
import org.springframework.security.config.annotation.web.configuration.EnableWebSecurity;
import org.springframework.security.config.annotation.web.configurers.AbstractHttpConfigurer;
import org.springframework.security.crypto.bcrypt.BCryptPasswordEncoder;
import org.springframework.security.crypto.password.PasswordEncoder;
import org.springframework.security.web.SecurityFilterChain;
import org.springframework.security.web.access.expression.WebExpressionAuthorizationManager;
import org.springframework.security.web.authentication.rememberme.JdbcTokenRepositoryImpl;
import org.springframework.security.web.authentication.rememberme.PersistentTokenRepository;

import javax.sql.DataSource;

import static org.springframework.security.config.Customizer.withDefaults;

@Configuration
@EnableWebSecurity
public class SecurityConfig {

    @Resource
    private MyAccessDeniedHandler myAccessDeniedHandler;

    @Resource
    private UserDetailsServiceImpl userDetailsService;

    @Resource
    private DataSource dataSource; //数据源对象

    @Bean
    public SecurityFilterChain securityFilterChain(HttpSecurity http) throws Exception {
        http.formLogin(formLoginSpec -> formLoginSpec
                .usernameParameter("user")
                .passwordParameter("pwd")
                // 自定义登录页面
                .loginPage("/tologin")
                // 当发现/doLogin时认为是登录提交请求，就进行放行
                .loginProcessingUrl("/doLogin")
                // 配置登录成功后的跳转页面
                .successForwardUrl("/toMain")
//                .successHandler(new MyAuthenticationSuccessHandler("http://www.baidu.com"))
                // 配置登录失败后的跳转页面
                .failureForwardUrl("/toError")
//                .failureHandler(new MyAuthenticationFailureHandler("/toError"))
                .permitAll());

        // 授权认证.
        // 设置除了登录页面，其他所有请求必须被认证后才能进行访问
        http.authorizeHttpRequests((authz) -> authz
                        // 设置/tologin不需要被认证，premitAll允许任何人都可以访问
                        .requestMatchers("/tologin").permitAll()
                        // toError错误页面, 不需要认证
//                        .requestMatchers("/toError").permitAll()
                        .requestMatchers("/tologin", "/toError", "/demo").permitAll()
                        .requestMatchers("/css/**", "/js/**", "/images/**").permitAll()
//                .requestMatchers("/toMain1").hasAnyAuthority("admiN")

//                        .requestMatchers("/toMain1").hasRole("abc")

//                        .requestMatchers("/toMain1").access(new WebExpressionAuthorizationManager(
//                                "isAuthenticated() and hasIpAddress('127.0.0.1')"))

                        // anyRequest()表示所有的请求，authenticated()表示登录认证后
                        // 即所有请求都必须被登录认证后才能进行访问
                        .anyRequest().authenticated()
        ).httpBasic(Customizer.withDefaults());

        // 配置异常处理
        http.exceptionHandling((ex) ->
                ex.accessDeniedHandler(myAccessDeniedHandler));

        // 记住我功能
        http.rememberMe((me) -> me
                //设置失效时间为60秒
                .tokenValiditySeconds(60)
                .userDetailsService(userDetailsService)
                //持久化对象
                .tokenRepository(getPersistentTokenRepository())
        );
        //退出登录
        http.logout((out->out
            //配置退出登录后跳转路劲
                .logoutSuccessUrl("/tologin")
        ));

        // 关闭 csrf 防火墙
        http.csrf(AbstractHttpConfigurer::disable);
        return http.build();


    }

    @Bean
    public PersistentTokenRepository getPersistentTokenRepository() {
        JdbcTokenRepositoryImpl jdbcTokenRepository = new JdbcTokenRepositoryImpl();

        //设置数据源对象
        jdbcTokenRepository.setDataSource(dataSource);
        //设置保存[记住我]的用户信息表,setCreateTableStartup(true)表示自动创建这张表
        //注意:第一次启动的时候需要使用下面这行代码创建表, 第二次启动之前则要把这行代码注释掉
//        jdbcTokenRepository.setCreateTableOnStartup(false); // 关键：禁用自动建表
//        jdbcTokenRepository.setCreateTableOnStartup(true);
        return jdbcTokenRepository;
    }
//    @Bean
//    public PasswordEncoder passwordEncoder() {
//        return new BCryptPasswordEncoder();
//    }
}